package com.katesoft.scale4j.rttp.client;

import java.io.Serializable;

import com.katesoft.scale4j.rttp.internal.AppContext;

/**
 * This class is created as helper class for distribution task executions.
 * <p/>
 * The problem that distributed frameworks, such as used in jvmcluster(hazelcast, quartz, spring
 * batch) are able to work only with serializable objects because they are trying to transfer data
 * through network or even persist internal state into database.
 * <p/>
 * It is clear that it is impossible and does not make any sense to serialize spring application
 * context.
 * <p/>
 * So this interface should provide a way to access spring context in distributed env.
 * 
 * @author kate2007
 */
public interface ISpringContextAccessor extends Serializable {
   ISpringContextAccessor ACCESSOR = new SpringContextAccessor();

   /**
    * looking up bean by name.
    * 
    * @param bean
    *           name of bean
    * @return bean from application context.
    */
   Object getBean(String bean);

   /**
    * looking up bean by name and given class.
    * 
    * @param bean
    *           name of bean
    * @param clazz
    *           expected class
    * @return bean from application context.
    */
   <T> T getBean(String bean, Class<T> clazz);

   /**
    * Populate the given bean instance through applying after-instantiation callbacks and bean
    * property post-processing (e.g. for annotation-driven injection).
    * 
    * @param bean
    *           object to run autowiring on
    * @return passed bean
    * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBean(Object)
    */
   <T> T autowire(T bean);

   /**
    * @author kate2007
    */
   class SpringContextAccessor implements ISpringContextAccessor {
      private static final long serialVersionUID = -6880597697612369854L;

      @Override
      public Object getBean(String bean) {
         return AppContext.getApplicationContext().getBean(bean);
      }

      @Override
      public <T> T getBean(String bean, Class<T> clazz) {
         return AppContext.getApplicationContext().getBean(bean, clazz);
      }

      @Override
      public <T> T autowire(T bean) {
         AppContext.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(bean);
         return bean;
      }
   }
}
